package br.com.localfloripa.controllers;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;
import javax.inject.Inject;
import javax.inject.Named;

import org.primefaces.event.RateEvent;
import org.primefaces.model.LazyDataModel;
import org.primefaces.model.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;

import br.com.localfloripa.dao.AnuncioDao;
import br.com.localfloripa.dao.AuditoriaDao;
import br.com.localfloripa.dao.ClienteDao;
import br.com.localfloripa.dao.ImovelDao;
import br.com.localfloripa.dao.MensagemDao;
import br.com.localfloripa.dao.MunicipioDao;
import br.com.localfloripa.entities.Anuncio;
import br.com.localfloripa.entities.Auditoria;
import br.com.localfloripa.entities.Avaliacao;
import br.com.localfloripa.entities.Cliente;
import br.com.localfloripa.entities.Estado;
import br.com.localfloripa.entities.Imovel;
import br.com.localfloripa.entities.Mensagem;
import br.com.localfloripa.entities.Municipio;
import br.com.localfloripa.entities.Proprietario;
import br.com.localfloripa.entities.TipoAuditoria;
import br.com.localfloripa.entities.TipoAvaliacao;
import br.com.localfloripa.entities.TipoNegociacao;

@Named("searchImovelController")
@Scope("session")
public class SearchImovelController implements Serializable {

	private static final long serialVersionUID = 5815946570654456419L;
	private static final Logger log = LoggerFactory.getLogger(SearchImovelController.class);
	private final Integer pageSize = 10;
	
	@Inject
	@Named("municipioDao")
	private MunicipioDao municipioDao;
	
	@Inject
	@Named("anuncioDao")
	private AnuncioDao anuncioDao;
	
	@Inject
	@Named("imovelDao")
	private ImovelDao imovelDao;
	
	@Inject
	@Named("clienteDao")
	private ClienteDao clienteDao;
	
	@Inject
	@Named("auditoriaDao")
	private AuditoriaDao auditoriaDao;
	
	@Inject
	@Named("mensagemDao")
	private MensagemDao mensagemDao;
	
	private String tipoNegociacao;
	private Estado estado;
	private Municipio municipio;
	private String[] selectedBairro;
	private Anuncio anuncio;
	private Imovel imovel;
	private Avaliacao avaliacao;
	private Mensagem mensagem;
	private Cliente cliente;
	private String dormitorios;
	private String garagens;
	private String suites;
	private String banheiros;
	private Boolean album;
	
	private List<String> bairros;
	private List<Estado> estados; 
	private List<Municipio> municipios;
	private Boolean searched;
	private Imovel destaque;
	
	private LazyDataModel<Imovel> lazyModelAnuncio; 
	
	
	public SearchImovelController() {
		
	}

	public String getTipoNegociacao() {
		return tipoNegociacao;
	}

	public void setTipoNegociacao(String tipoNegociacao) {
		this.tipoNegociacao = tipoNegociacao;
	}

	public Estado getEstado() {
		return estado;
	}

	public void setEstado(Estado estado) {
		this.estado = estado;
	}

	public Municipio getMunicipio() {
		return municipio;
	}

	public void setMunicipio(Municipio municipio) {
		this.municipio = municipio;
	}

	public String[] getSelectedBairro() {
		return selectedBairro;
	}

	public void setSelectedBairro(String[] selectedBairro) {
		this.selectedBairro = selectedBairro;
	}

	public Cliente getCliente() {
		return cliente;
	}

	public void setCliente(Cliente cliente) {
		this.cliente = cliente;
	}

	public Avaliacao getAvaliacao() {
		return avaliacao;
	}

	public void setAvaliacao(Avaliacao avaliacao) {
		this.avaliacao = avaliacao;
	}

	public Mensagem getMensagem() {
		return mensagem;
	}

	public void setMensagem(Mensagem mensagem) {
		this.mensagem = mensagem;
	}

	public String getDormitorios() {
		return dormitorios;
	}

	public void setDormitorios(String dormitorios) {
		this.dormitorios = dormitorios;
	}

	public String getGaragens() {
		return garagens;
	}

	public void setGaragens(String garagens) {
		this.garagens = garagens;
	}

	public String getSuites() {
		return suites;
	}

	public void setSuites(String suites) {
		this.suites = suites;
	}

	public String getBanheiros() {
		return banheiros;
	}

	public void setBanheiros(String banheiros) {
		this.banheiros = banheiros;
	}

	public Boolean getAlbum() {
		return album;
	}

	public void setAlbum(Boolean album) {
		this.album = album;
	}

	public List<String> getBairros() {
		return bairros;
	}

	public void setBairros(List<String> bairros) {
		this.bairros = bairros;
	}

	public MunicipioDao getMunicipioDao() {
		return municipioDao;
	}

	public void setMunicipioDao(MunicipioDao municipioDao) {
		this.municipioDao = municipioDao;
	}

	public List<Estado> getEstados() {
		return estados;
	}

	public void setEstados(List<Estado> estados) {
		this.estados = estados;
	}

	public List<Municipio> getMunicipios() {
		return municipios;
	}

	public void setMunicipios(List<Municipio> municipios) {
		this.municipios = municipios;
	}

	public Anuncio getAnuncio() {
		return anuncio;
	}

	public void setAnuncio(Anuncio anuncio) {
		this.anuncio = anuncio;
	}

	public Imovel getImovel() {
		return imovel;
	}

	public void setImovel(Imovel imovel) {
		this.imovel = imovel;
	}

	public Imovel getDestaque() {
		return destaque;
	}

	public void setDestaque(Imovel destaque) {
		this.destaque = destaque;
	}

	public Integer getPageSize() {
		return pageSize;
	}

	public LazyDataModel<Imovel> getLazyModelAnuncio() {
		return lazyModelAnuncio;
	}

	public void setLazyModelAnuncio(LazyDataModel<Imovel> lazyModelAnuncio) {
		this.lazyModelAnuncio = lazyModelAnuncio;
	}
	
	public Boolean getSearched() {
		return searched;
	}

	public Boolean getLancamentos() {
		Boolean lancamentos = false;
		try {
			lancamentos = anuncioDao.verificaLancamentos(cliente);
		} catch (Exception e) {
			lancamentos = false;
			log.error(e.getMessage(),e);
		}
		return lancamentos;
	}
	
	public List<Imovel> getTopLancamentos() {		
		try {
			return anuncioDao.listTopLancamentos(cliente);
		} catch (Exception e) {
			log.error(e.getMessage(),e);
			return null;
		}		
	}

	public void setSearched(Boolean searched) {
		this.searched = searched;
	}

	public void loadImoveis() {

		try {	
			
			String idCliente = (String) FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get("id");
			if (idCliente != null)
				this.cliente = clienteDao.findById(Long.parseLong(idCliente));
			
			lazyModelAnuncio = new LazyDataModel<Imovel>() {
	
				@Override
				public List<Imovel> load(int first, int pageSize, String sortField, SortOrder order, Map<String, String> filters) {
					List<Imovel> anuncios = null;
					try {				
						anuncios = anuncioDao.searchAnunciosPaginadaByCliente(cliente, first, pageSize);					
					} catch (Exception e) {
						log.error(e.getMessage(),e);
					}
					return anuncios;
				}
	
				@Override
				public int getRowCount() {
					return anuncioDao.countAnunciosByCliente(cliente).intValue();
				}
	
				@Override
				public int getPageSize() {
					return pageSize;
				}
				
				@Override  
			    public Object getRowKey(Imovel imovel) {  
			        return imovel.getId();  
			    } 
				
				@Override  
			    public Imovel getRowData(String rowKey) {  
					
					if (rowKey != null && !rowKey.equals("null")) {
						List<Imovel> imoveis = (List<Imovel>) getWrappedData();  
				          
				        for(Imovel imovel : imoveis) {  
				            if(imovel.getId().equals(Long.valueOf(rowKey)))  
				                return imovel;  
				        }
					}  		          
			        return null;  
			    }  
			};		
			this.destaque = anuncioDao.getDestaque(cliente);
			
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		}		
		this.avaliacao = new Avaliacao();	
		this.mensagem = new Mensagem();
		this.anuncio = new Anuncio();
		this.municipio = new Municipio();
		this.estado = new Estado();
		this.searched = false;
		
	}
	
	public String search() {
		
		lazyModelAnuncio = new LazyDataModel<Imovel>() {

			@Override
			public List<Imovel> load(int first, int pageSize, String sortField, SortOrder order, Map<String, String> filters) {
				List<Imovel> anuncios = null;
				try {						
					anuncios = anuncioDao.searchImoveisPaginada(cliente, tipoNegociacao, municipio, selectedBairro, dormitorios, garagens,banheiros,suites,album,first,pageSize);
				} catch (Exception e) {
					log.error(e.getMessage(),e);
				}
				return anuncios;
			}

			@Override
			public int getRowCount() {
				try {
					return anuncioDao.countImoveis(cliente, tipoNegociacao, municipio, selectedBairro, dormitorios, garagens,banheiros,suites,album).intValue();
				} catch (Exception e) {
					log.error(e.getMessage(),e);
					return 0;
				}
			}

			@Override
			public int getPageSize() {
				return pageSize;
			}	
			
			@Override  
		    public Object getRowKey(Imovel imovel) {  
		        return imovel.getId();  
		    } 
			
			@Override  
		    public Imovel getRowData(String rowKey) {  
				
				if (rowKey != null && !rowKey.equals("null")) {
					List<Imovel> imoveis = (List<Imovel>) getWrappedData();  
			          
			        for(Imovel imovel : imoveis) {  
			            if(imovel.getId().equals(Long.valueOf(rowKey)))  
			                return imovel;  
			        }
				}  		          
		        return null;  
		    }  
		};
		
		try {
			this.destaque = anuncioDao.getDestaque(cliente);
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		}
		this.avaliacao = new Avaliacao();	
		this.mensagem = new Mensagem();
		this.anuncio = new Anuncio();	
		this.searched = true;
		
		return "/faces/site/xhtml/templates/complex-body.xhtml";
	}
	
	public String loadLancamentos() {
		try {
			String idCliente = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("idCliente");
			cliente =  clienteDao.findById(Long.parseLong(idCliente));
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		}		
		
		lazyModelAnuncio = new LazyDataModel<Imovel>() {

			@Override
			public List<Imovel> load(int first, int pageSize, String sortField, SortOrder order, Map<String, String> filters) {
				List<Imovel> anuncios = null;
				try {						
					anuncios = anuncioDao.listLancamentos(cliente, first, pageSize);
				} catch (Exception e) {
					log.error(e.getMessage(),e);
				}
				return anuncios;
			}

			@Override
			public int getRowCount() {
				try {
					return anuncioDao.countLancamentos(cliente).intValue();
				} catch (Exception e) {
					log.error(e.getMessage(),e);
					return 0;
				}
			}

			@Override
			public int getPageSize() {
				return pageSize;
			}
			
			@Override  
		    public Object getRowKey(Imovel imovel) {  
		        return imovel.getId();  
		    } 
			
			@Override  
		    public Imovel getRowData(String rowKey) {  
				
				if (rowKey != null && !rowKey.equals("null")) {
					List<Imovel> imoveis = (List<Imovel>) getWrappedData();  
			          
			        for(Imovel imovel : imoveis) {  
			            if(imovel.getId().equals(Long.valueOf(rowKey)))  
			                return imovel;  
			        }
				}  		          
		        return null;  
		    }  
		};
		
		try {
			this.destaque = anuncioDao.getDestaque(cliente);
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		}
		this.avaliacao = new Avaliacao();	
		this.mensagem = new Mensagem();
		this.anuncio = new Anuncio();	
		this.searched = true;
		
		return "/faces/site/xhtml/templates/complex-body.xhtml";
	}
	
	public String loadImoveisVenda() {
		
		try {
			String idCliente = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("idCliente");
			cliente =  clienteDao.findById(Long.parseLong(idCliente));
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		}		
		
		lazyModelAnuncio = new LazyDataModel<Imovel>() {

			@Override
			public List<Imovel> load(int first, int pageSize, String sortField, SortOrder order, Map<String, String> filters) {
				List<Imovel> anuncios = null;
				try {						
					anuncios = anuncioDao.listImoveisByTipoNegociacao(cliente,TipoNegociacao.V,first, pageSize);
				} catch (Exception e) {
					log.error(e.getMessage(),e);
				}
				return anuncios;
			}

			@Override
			public int getRowCount() {
				try {
					return anuncioDao.countImoveisByTipoNegociacao(cliente,TipoNegociacao.V).intValue();
				} catch (Exception e) {
					log.error(e.getMessage(),e);
					return 0;
				}
			}

			@Override
			public int getPageSize() {
				return pageSize;
			}	
			
			@Override  
		    public Object getRowKey(Imovel imovel) {  
		        return imovel.getId();  
		    } 
			
			@Override  
		    public Imovel getRowData(String rowKey) {  
				
				if (rowKey != null && !rowKey.equals("null")) {
					List<Imovel> imoveis = (List<Imovel>) getWrappedData();  
			          
			        for(Imovel imovel : imoveis) {  
			            if(imovel.getId().equals(Long.valueOf(rowKey)))  
			                return imovel;  
			        }
				}  		          
		        return null;  
		    }  
		};
		
		try {
			this.destaque = anuncioDao.getDestaque(cliente);
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		}
		this.avaliacao = new Avaliacao();	
		this.mensagem = new Mensagem();
		this.anuncio = new Anuncio();	
		this.searched = true;
		
		return "/faces/site/xhtml/templates/complex-body.xhtml";		
	}
	
	public String loadImoveisAluguel() {
		
		try {
			String idCliente = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("idCliente");
			cliente =  clienteDao.findById(Long.parseLong(idCliente));
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		}		
		
		lazyModelAnuncio = new LazyDataModel<Imovel>() {

			@Override
			public List<Imovel> load(int first, int pageSize, String sortField, SortOrder order, Map<String, String> filters) {
				List<Imovel> anuncios = null;
				try {						
					anuncios = anuncioDao.listImoveisByTipoNegociacao(cliente,TipoNegociacao.A,first, pageSize);
				} catch (Exception e) {
					log.error(e.getMessage(),e);
				}
				return anuncios;
			}

			@Override
			public int getRowCount() {
				try {
					return anuncioDao.countImoveisByTipoNegociacao(cliente,TipoNegociacao.A).intValue();
				} catch (Exception e) {
					log.error(e.getMessage(),e);
					return 0;
				}
			}

			@Override
			public int getPageSize() {
				return pageSize;
			}	
			
			@Override  
		    public Object getRowKey(Imovel imovel) {  
		        return imovel.getId();  
		    } 
			
			@Override  
		    public Imovel getRowData(String rowKey) {  
				
				if (rowKey != null && !rowKey.equals("null")) {
					List<Imovel> imoveis = (List<Imovel>) getWrappedData();  
			          
			        for(Imovel imovel : imoveis) {  
			            if(imovel.getId().equals(Long.valueOf(rowKey)))  
			                return imovel;  
			        }
				}  		          
		        return null;  
		    }  
		};
		
		try {
			this.destaque = anuncioDao.getDestaque(cliente);
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		}
		this.avaliacao = new Avaliacao();	
		this.mensagem = new Mensagem();
		this.anuncio = new Anuncio();	
		this.searched = true;
		
		return "/faces/site/xhtml/templates/complex-body.xhtml";		
	}
	
	public final List<SelectItem> getTiposNegociacao() {
		List<SelectItem> items = new ArrayList<SelectItem>();
		for ( TipoNegociacao tipo: TipoNegociacao.values() ) {
			items.add(new SelectItem(tipo.name(), tipo.value()));
		}
		return items;
	}
	
	public void reloadBairros() {
		try {
			this.bairros = municipioDao.listBairrosByMunicipioAndCliente(municipio, cliente);						
		} catch (Exception e) {
			log.error(e.getMessage());
			this.bairros = new ArrayList<String>();
		}					
	}
	
	public void reloadMunicipios() {
		try {
			this.municipios = municipioDao.listMunicipiosByEstadoAndCliente(estado, cliente);
		} catch (Exception e) {
			log.error(e.getMessage());
			this.municipios = new ArrayList<Municipio>();
		}				
	}
	
	public void loadAnuncioById() {
		try {			
			String idAnuncio = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("idAnuncio");
			if (idAnuncio != null)
				this.anuncio = anuncioDao.forceEagerLoad(Long.parseLong(idAnuncio));
						
		} catch (NumberFormatException e) {
			log.error(e.getMessage(),e);
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		}
	}
	
	public void loadImovelById() {
		try {			
			String idImovel = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("idImovel");
			if (idImovel != null)
				this.imovel = imovelDao.findById(Long.parseLong(idImovel));
						
		} catch (NumberFormatException e) {
			log.error(e.getMessage(),e);
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		}
	}
	
	public void auditarClick() {
		try {			
			String tipoAuditoria = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("tipo");
			TipoAuditoria tipo = TipoAuditoria.valueOf(tipoAuditoria);
			
			String idAnuncio = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("idAnuncio");
			
			if (idAnuncio != null)
				this.anuncio = anuncioDao.findById(Long.parseLong(idAnuncio));
			
			Auditoria auditoria = new Auditoria();
			auditoria.setAnuncio(this.anuncio);
			auditoria.setTipo(tipo);
			auditoria.setData(Calendar.getInstance().getTime());
			
			auditoriaDao.persist(auditoria);						
		} catch (NumberFormatException e) {
			log.error(e.getMessage(),e);
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		}
	}
	
	public void loadSelectedAnuncio(RateEvent event) {
		
		UIComponent ratingComponent = event.getComponent();
        Long idAnuncio = (Long) ratingComponent.getAttributes().get("idAnuncio");
        String tipoAvaliacao = (String) ratingComponent.getAttributes().get("tipo");        
        try {
			this.anuncio = anuncioDao.forceEagerLoad(idAnuncio);
			this.avaliacao.setClassificacao((Double)event.getRating());
			if (TipoAvaliacao.A.name().equals(tipoAvaliacao)) {
				this.avaliacao.setTipo(TipoAvaliacao.A);
			} else {
				this.avaliacao.setTipo( TipoAvaliacao.S );
			}			
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		}        		
	}
	
	public void handleRate() {
		
		try {
			List<Avaliacao> avaliacoes = this.anuncio.getAvaliacoes();
			if (avaliacoes != null) {
				avaliacoes.add(this.avaliacao);
			} else {
				avaliacoes = new ArrayList<Avaliacao>();
				avaliacoes.add(this.avaliacao);
			}
			this.anuncio.setAvaliacoes(avaliacoes);
			anuncioDao.merge(this.anuncio);
			if (this.avaliacao.getTipo().name().equals(TipoAvaliacao.A.name())) {
				this.anuncio.setReputacaoAtendimento( anuncioDao.calculaReputacao(anuncio,TipoAvaliacao.A));
			} else {
				this.anuncio.setReputacaoServico( anuncioDao.calculaReputacao(anuncio,TipoAvaliacao.S));
			}			
			anuncioDao.merge(this.anuncio);
			this.avaliacao = new Avaliacao();
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		} 
	}
	
	
	public void sendMessage() {
		
		try {
			List<Mensagem> mensagens = this.anuncio.getMensagens();			
			this.mensagem.setDataEnvio(Calendar.getInstance().getTime());
			if (mensagens != null) {
				mensagens.add(this.mensagem);
			} else {
				mensagens = new ArrayList<Mensagem>();
				mensagens.add(this.mensagem);
			}
			this.anuncio.setMensagens(mensagens);
			anuncioDao.merge(this.anuncio);
				
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		}				
	}
	
	public void sendDirectMessage() {
		
		ResourceBundle bundle = ResourceBundle.getBundle("messages.MessageBundle");
		try {
			String idCliente = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("idCliente");
			cliente =  clienteDao.findById(Long.parseLong(idCliente));
			
			this.mensagem.setDataEnvio(Calendar.getInstance().getTime());
			this.mensagem.setRemetente(cliente);
			mensagemDao.persist(this.mensagem);
			/** reseta objeto mensagem **/
			this.mensagem = new Mensagem();
						
			FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO,
					bundle.getString("messages.sumary.info.confirm"), bundle.getString("message.direct.confirm")));  
			
		} catch (Exception e) {
			log.error(e.getMessage(),e);
			FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR,
					bundle.getString("messages.sumary.error"), bundle.getString("message.direct.error"))); 			
		}				
	}
	
	public final List getProprietarios() {
		List typeOptions = new ArrayList();
		for (Proprietario prop : Proprietario.values()) {
			typeOptions.add(new SelectItem(prop.name(), prop.value()));
		}
		return typeOptions;
	}
	
	
}
